﻿using BCCommon;
using BCData.MakeStaticPagingComponent.PageTemplate;
using BCData.MakeStaticPagingComponent.TemplateTag;
using BCData.MakeStaticPagingComponent.WebsiteTemplate;
using BCDto.MakeStaticPagingComponent.PageTemplate;
using BCEntity.MakeStaticPagingComponent.PageTemplate;
using BCEntity.MakeStaticPagingComponent.WebsiteTemplate;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace BCService.MakeStaticPagingComponent.PageTemplateService
{
    /// <summary>
    /// 页面模板服务
    /// </summary>
    public class PageTemplateService : IPageTemplateService
    {
        private readonly IPageTemplateData pageTemplateData;
        private readonly IWebsiteTemplateData websiteTemplateData;
        public PageTemplateService(IPageTemplateData pageTemplateData,
            IWebsiteTemplateData websiteTemplateData)
        {
            this.pageTemplateData = pageTemplateData;
            this.websiteTemplateData = websiteTemplateData;
        }

        public PageTemplateDto Add(PageTemplateRequestDto pageTemplateRequestDto)
        {
            if (!this.websiteTemplateData.CheckWebsiteTemplateExists(pageTemplateRequestDto.WebsiteTemplateId))
            {
                throw new ArgumentException("网站模板不存在。");
            }
            if (this.pageTemplateData.CheckPageTemplateExists(pageTemplateRequestDto.PageUrlName, pageTemplateRequestDto.WebsiteTemplateId))
            {
                throw new ArgumentException("页面模板路径名称已经存在。");
            }
            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.ParentPageCode) && !this.pageTemplateData.CheckParentPageTemplateExists(pageTemplateRequestDto.WebsiteTemplateId, pageTemplateRequestDto.ParentPageCode))
            {
                throw new ArgumentException("父级页面模板不存在。");
            }
            if (this.pageTemplateData.CheckPageCodeExists(pageTemplateRequestDto.PageCode))
            {
                throw new ArgumentException("页面编码已存在。");
            }
            if (pageTemplateRequestDto.IsPagingListPage && (!pageTemplateRequestDto.ListSize.HasValue || pageTemplateRequestDto.ListSize.Value == 0))
            {
                throw new ArgumentException("此页面为分页列表页，分页每页数量需大于 0");
            }
            Regex regex = new Regex("[{]{2}#\\s*(?<TemplateTag>BCPagingTag)[^#]*\\s*#[}]{2}((?<Nested>[{]{2}#\\s*\\k<TemplateTag>[^#]*[}]{2})|[{]{2}#\\s*/\\k<TemplateTag>\\s*#[}]{2}(?<-Nested>)|.*?)*[{]{2}#\\s*/\\k<TemplateTag>\\s*#[}]{2}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
            if (regex.IsMatch(pageTemplateRequestDto.PageHtml))
            {
                MatchCollection matchCollection = regex.Matches(pageTemplateRequestDto.PageHtml);
                if (matchCollection.Count > 1 && pageTemplateRequestDto.IsPagingListPage)
                {
                    throw new ArgumentException("分页列表页内仅支持存在一个BCPagingTag标签！！！");
                }
            }
            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.PageDefine) && pageTemplateRequestDto.PageDefine.IndexOf(";") > -1)
            {
                regex = new Regex("[&]{2}\\w*\\s*[=]\\s*(([&$#]{2}[a-zA-Z_0-9]+([(](([\"\'][a-zA-Z_0-9]+[\"\'][,] ?)*|((\\d +)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)])?)|(\\w+[(](([\"\'][a-zA-Z_0-9]+[\"\'][,]?)*|((\\d+)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)])?|([\"\'][a-zA-Z_0-9]+[\"\'])*|(\\d*[.]?\\d*)*|([\\d]*[.][\\d]+[,]?)*)?");
                string[] pageDataDefines = pageTemplateRequestDto.PageDefine.Split(";");
                foreach (string item in pageDataDefines)
                {
                    if (!regex.IsMatch(item))
                    {
                        throw new ArgumentException(string.Format("页面数据定义变量不正确！定义错误语句：{0}", item));
                    }
                }
            }
            PageTemplateEntity entity = pageTemplateRequestDto.As<PageTemplateEntity>();
            entity.IsPagingListPage = pageTemplateRequestDto.IsPagingListPage;
            entity.PagingListServiceTag = pageTemplateRequestDto.PagingListServiceTag;
            entity.PagingListServiceParams = pageTemplateRequestDto.PagingListServiceParams;

            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.ParentPageCode))
            {
                PageTemplateEntity parentEntity = this.pageTemplateData.Get(pageTemplateRequestDto.ParentPageCode, pageTemplateRequestDto.WebsiteTemplateId);
                if (parentEntity.IsContentPage)
                {
                    throw new ArgumentException("当前所选父级页面为内容页，无法创建内容页子级页面!");
                }
                if (parentEntity.IsPagingListPage)
                {
                    if (!string.IsNullOrWhiteSpace(parentEntity.PageCode))
                    {
                        var pagingListPageEntities = this.pageTemplateData.GetPageTemplateChildren(parentEntity.WebsiteTemplateId, parentEntity.PageCode).Result;
                        if (pagingListPageEntities.Any(p => p.IsContentPage))
                        {
                            throw new ArgumentException("当前所选父级页面为分页列表页，且此父级页面已存在子级内容页，无法创建多个子级内容页面模板!");
                        }
                    }
                }
                entity.PageLevel = ++parentEntity.PageLevel;
                entity.PageLevelCode = string.Concat(parentEntity.PageLevelCode, ",", pageTemplateRequestDto.PageCode);
            }
            else
            {
                entity.PageLevel = 0;
                entity.PageLevelCode = pageTemplateRequestDto.PageCode;
            }
            WebsiteTemplateEntity websiteTemplateEntity = websiteTemplateData.Get(entity.WebsiteTemplateId);
            if (websiteTemplateEntity.IsUsed)
            {
                entity.IsUsed = true;
            }
            else
            {
                entity.IsUsed = false;
            }
            if (!entity.IsPagingListPage && !entity.IsContentPage)
            {
                entity.SystemServiceListingId = null;
            }


            //TODO:缺少检查页面归属网站模板是否为已使用，如果是，则修改页面为已使用，否则为未使用。
            return this.pageTemplateData.Add(entity).As<PageTemplateDto>();
        }

        public PageTemplateDto Get(string pageCode, int websiteTemplateId)
        {
            return this.pageTemplateData.Get(pageCode, websiteTemplateId).As<PageTemplateDto>();
        }

        public PageTemplateDto Get(long pageTemplateId)
        {
            return this.pageTemplateData.Get(pageTemplateId).As<PageTemplateDto>();
        }

        public PageableList<PageTemplateDto> Get(string pageName, int websiteTemplateId, bool? ascending, int index = 1, int size = 20)
        {
            var list = this.pageTemplateData.Get(pageName, websiteTemplateId, out int dataCount, ascending, index, size);

            var allList = this.pageTemplateData.GetList(websiteTemplateId);

            var result = new List<PageTemplateDto>();
            foreach (PageTemplateEntity entity in list)
            {
                PageTemplateDto dto = entity.As<PageTemplateDto>();
                dto.Key = dto.PageTemplateId.ToString();
                if (!allList.Any(p => !string.IsNullOrWhiteSpace(p.ParentPageCode) && p.ParentPageCode.Equals(dto.PageCode)))
                {
                    result.Add(dto);
                }
                else
                {
                    var children = GetPageTemplateChildren(allList, dto.Key, dto.PageCode);
                    dto.Children = children;
                    result.Add(dto);
                }
            }

            return new PageableList<PageTemplateDto>
            {
                Count = dataCount,
                Items = result
            };
        }

        public IEnumerable<PageTemplateDto> GetAllPageTemplateList()
        {
            return this.pageTemplateData.Get().As<IEnumerable<PageTemplateDto>>();
        }

        public IEnumerable<PageTemplateDto> GetSubPageTemplateList(string pageCode)
        {
            return this.pageTemplateData.GetSubPageTemplateList(pageCode).As<IEnumerable<PageTemplateDto>>();
        }
        public IEnumerable<PageTemplateDto> GetShowNavigationSubPageTemplateList(string pageCode)
        {
            return this.pageTemplateData.GetShowNavigationSubPageTemplateList(pageCode).As<IEnumerable<PageTemplateDto>>();
        }

        public PageTemplateDto Update(long pageTemplateId, PageTemplateRequestDto pageTemplateRequestDto)
        {
            if (!this.websiteTemplateData.CheckWebsiteTemplateExists(pageTemplateRequestDto.WebsiteTemplateId))
            {
                throw new ArgumentException("网站模板不存在。");
            }
            if (pageTemplateRequestDto.IsPagingListPage && (!pageTemplateRequestDto.ListSize.HasValue || pageTemplateRequestDto.ListSize.Value == 0))
            {
                throw new ArgumentException("此页面为分页列表页，分页每页数量需大于 0");
            }
            Regex regex = new Regex("[{]{2}#\\s*(?<TemplateTag>BCPagingTag)[^#]*\\s*#[}]{2}((?<Nested>[{]{2}#\\s*\\k<TemplateTag>[^#]*[}]{2})|[{]{2}#\\s*/\\k<TemplateTag>\\s*#[}]{2}(?<-Nested>)|.*?)*[{]{2}#\\s*/\\k<TemplateTag>\\s*#[}]{2}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
            if (regex.IsMatch(pageTemplateRequestDto.PageHtml))
            {
                MatchCollection matchCollection = regex.Matches(pageTemplateRequestDto.PageHtml);
                if (matchCollection.Count > 1 && pageTemplateRequestDto.IsPagingListPage)
                {
                    throw new ArgumentException("分页列表页内仅支持存在一个BCPagingTag标签！！！");
                }
            }
            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.PageDefine) && pageTemplateRequestDto.PageDefine.IndexOf(";") > -1)
            {
                regex = new Regex("[&]{2}\\w*\\s*[=]\\s*(([&$#]{2}[a-zA-Z_0-9]+([(](([\"\'][a-zA-Z_0-9]+[\"\'][,] ?)*|((\\d +)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)])?)|(\\w+[(](([\"\'][a-zA-Z_0-9]+[\"\'][,]?)*|((\\d+)[,]?)*|([\\d]*[.][\\d]+[,]?)*)*[)]?)?|([\"\'][a-zA-Z_0-9]+[\"\'])*|(\\d*[.]?\\d*)*|([\\d]*[.][\\d]+[,]?)*)?");
                string[] pageDataDefines = pageTemplateRequestDto.PageDefine.Split(";", StringSplitOptions.RemoveEmptyEntries);
                IEnumerable<string> list = pageDataDefines.Where(p => string.IsNullOrWhiteSpace(p.Trim()));
                foreach (string item in list)
                {
                    if (!regex.IsMatch(item))
                    {
                        throw new ArgumentException(string.Format("页面数据定义变量不正确！定义错误语句：{0}", item));
                    }
                }
            }
            PageTemplateEntity entity = this.pageTemplateData.Get(pageTemplateId);
            if (entity == null)
            {
                throw new ArgumentException("此页面模板不正确。");
            }
            if (!entity.PageName.Equals(pageTemplateRequestDto.PageName))
            {
                entity.PageName = pageTemplateRequestDto.PageName;
            }
            if (!entity.PageUrlName.Equals(pageTemplateRequestDto.PageUrlName))
            {
                if (this.pageTemplateData.CheckPageTemplateExists(pageTemplateRequestDto.PageUrlName, pageTemplateRequestDto.WebsiteTemplateId, pageTemplateId))
                {
                    throw new ArgumentException("此url显示名称已存在。");
                }
                else
                {
                    entity.PageUrlName = pageTemplateRequestDto.PageUrlName;
                }
            }

            if (!entity.PageCode.Equals(pageTemplateRequestDto.PageCode))
            {
                if (this.pageTemplateData.CheckPageTemplateExists(pageTemplateRequestDto.WebsiteTemplateId, pageTemplateRequestDto.PageCode, pageTemplateId))
                {
                    throw new ArgumentException("此页面标记码已存在。");
                }
                else
                {
                    entity.PageCode = pageTemplateRequestDto.PageCode;
                }
            }

            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.ParentPageCode))
            {
                if (!this.pageTemplateData.CheckParentPageTemplateExists(pageTemplateRequestDto.WebsiteTemplateId, pageTemplateRequestDto.ParentPageCode))
                {
                    throw new ArgumentException("父级页面模板不已经存在。");
                }
                else
                {
                    entity.ParentPageCode = pageTemplateRequestDto.ParentPageCode;
                }
            }
            if (!string.IsNullOrWhiteSpace(pageTemplateRequestDto.ParentPageCode))
            {
                PageTemplateEntity parentEntity = this.pageTemplateData.Get(pageTemplateRequestDto.ParentPageCode, pageTemplateRequestDto.WebsiteTemplateId);
                if (parentEntity.IsContentPage)
                {
                    throw new ArgumentException("所选父级页面为内容页，无法创建内容页子级页面!");
                }
                if (parentEntity.IsPagingListPage)
                {
                    if (!string.IsNullOrWhiteSpace(parentEntity.ParentPageCode))
                    {
                        var pagingListPageEntities = this.pageTemplateData.GetPageTemplateChildren(parentEntity.WebsiteTemplateId, parentEntity.ParentPageCode).Result;
                        if (pagingListPageEntities.Any(p => p.IsContentPage && p.PageTemplateId != pageTemplateId))
                        {
                            throw new ArgumentException("当前所选父级页面为分页列表页，且此父级页面已存在子级内容页，无法创建多个子级内容页面模板!");
                        }
                    }
                }
                entity.PageLevel = ++parentEntity.PageLevel;
                entity.PageLevelCode = string.Concat(parentEntity.PageLevelCode, ",", pageTemplateRequestDto.PageCode);
            }
            else
            {
                entity.PageLevel = 0;
            }

            WebsiteTemplateEntity websiteTemplateEntity = websiteTemplateData.Get(entity.WebsiteTemplateId);

            if (websiteTemplateEntity.IsUsed)
            {
                entity.IsUsed = true;
            }
            else
            {
                entity.IsUsed = false;
            }
            entity.PageDefine = pageTemplateRequestDto.PageDefine;
            entity.PageHtml = pageTemplateRequestDto.PageHtml;
            entity.PageHtmlPath = pageTemplateRequestDto.PageHtmlPath;
            entity.PageKeyword = pageTemplateRequestDto.PageKeyword;
            entity.PageDescription = pageTemplateRequestDto.PageDescription;
            entity.IsContentPage = pageTemplateRequestDto.IsContentPage;
            entity.IsPagingListPage = pageTemplateRequestDto.IsPagingListPage;
            entity.PagingListServiceTag = pageTemplateRequestDto.PagingListServiceTag;
            entity.PagingListServiceParams = pageTemplateRequestDto.PagingListServiceParams;
            entity.SystemServiceListingId = pageTemplateRequestDto.SystemServiceListingId;
            entity.PageIndex = pageTemplateRequestDto.PageIndex;
            entity.ListSize = pageTemplateRequestDto.ListSize;
            entity.ContentPageCode = pageTemplateRequestDto.ContentPageCode;
            if (!entity.IsPagingListPage && !entity.IsContentPage)
            {
                entity.SystemServiceListingId = null;
            }
            var result = this.pageTemplateData.Update(entity);
            if (result == null)
            {
                throw new ArgumentException("修改页面模板失败!");
            }
            if (!result.IsContentPage)
            {
                var list = this.pageTemplateData.GetPageTemplateChildren(result.WebsiteTemplateId, result.PageCode).GetAwaiter().GetResult();
                if (list.Any(p => p.IsContentPage))
                {
                    var child = list.First(p => p.IsContentPage);
                    child.PagingListServiceTag = result.PagingListServiceTag;
                    child.PagingListServiceParams = result.PagingListServiceParams;
                    var childResult = this.pageTemplateData.Update(child).As<PageTemplateDto>();
                    if (childResult == null)
                    {
                        throw new ArgumentException("更新子级内容页信息失败!");
                    }
                }
            }
            return result.As<PageTemplateDto>();
        }

        public bool UpdateWebsiteTemplateIsUsed(int websiteTemplateId)
        {
            if (!this.websiteTemplateData.CheckWebsiteTemplateExists(websiteTemplateId))
            {
                throw new ArgumentException("网站模板不存在。");
            }
            return this.pageTemplateData.UpdateWebsiteTemplateIsUsed(websiteTemplateId);
        }

        public void Delete(long pageTemplateId)
        {
            PageTemplateEntity entity = this.pageTemplateData.Get(pageTemplateId);
            if (entity.IsSystem)
            {
                throw new ArgumentException("系统页面模板不允许删除！");
            }
            this.pageTemplateData.Delete(pageTemplateId);
        }

        public IEnumerable<PageTemplateDto> GetAnyWebsiteTemplateTree(long websiteTemplateId)
        {
            var list = this.pageTemplateData.GetList(websiteTemplateId);
            List<PageTemplateDto> pageTemplateDtos = new List<PageTemplateDto>();
            foreach (PageTemplateEntity entity in list.Where(p => p.PageLevel == 0).Select(p => p))
            {
                PageTemplateDto dto = entity.As<PageTemplateDto>();
                dto.Key = dto.PageTemplateId.ToString();
                if (!list.Any(p => !string.IsNullOrWhiteSpace(p.ParentPageCode) && p.ParentPageCode.Equals(dto.PageCode)))
                {
                    dto.IsLeaf = true;
                    pageTemplateDtos.Add(dto);
                }
                else
                {
                    var children = GetPageTemplateChildren(list, dto.Key, dto.PageCode);
                    dto.Children = children;
                    pageTemplateDtos.Add(dto);
                }
            }
            return pageTemplateDtos;
        }

        private List<PageTemplateDto> GetPageTemplateChildren(IEnumerable<PageTemplateEntity> pageTemplateEntities, string key, string pagecode)
        {
            List<PageTemplateDto> list = new List<PageTemplateDto>();
            foreach (PageTemplateEntity entity in pageTemplateEntities.Where(p => !string.IsNullOrWhiteSpace(p.ParentPageCode) && p.ParentPageCode.Equals(pagecode)))
            {
                PageTemplateDto dto = entity.As<PageTemplateDto>();
                dto.Key = string.Format("{0}-{1}", key, dto.PageTemplateId.ToString());

                if (pageTemplateEntities.Any(p => !string.IsNullOrWhiteSpace(p.ParentPageCode) && p.ParentPageCode.Equals(dto.PageCode)))
                {
                    var children = GetPageTemplateChildren(pageTemplateEntities, dto.Key, dto.PageCode);
                    dto.Children = children;
                    list.Add(dto);
                }
                else
                {
                    dto.IsLeaf = true;
                    list.Add(dto);
                }
            }
            return list;
        }

        public IEnumerable<PageTemplateDto> GetPageTemplateChildren(int websiteTemplateId, string parentPageCode)
        {
            Task<IEnumerable<PageTemplateEntity>> taskEntitiesResult = this.pageTemplateData.GetPageTemplateChildren(websiteTemplateId, parentPageCode);
            return taskEntitiesResult.GetAwaiter().GetResult().As<IEnumerable<PageTemplateDto>>();
        }

        public IEnumerable<PageTemplateDto> GetAllChild()
        {
            List<PageTemplateDto> list = new List<PageTemplateDto>();
            IEnumerable<PageTemplateDto> entities = this.pageTemplateData.GetTree().As<IEnumerable<PageTemplateDto>>();
            list = entities.Where(p => p.PageLevel == 1).ToList();
            foreach (var item in list)
            {
                item.Children.AddRange(PageTemplateList(item, entities));
            }
            return list.As<IEnumerable<PageTemplateDto>>();
        }

        private List<PageTemplateDto> PageTemplateList(PageTemplateDto entity, IEnumerable<PageTemplateDto> entities)
        {
            List<PageTemplateDto> list = new List<PageTemplateDto>();
            list = entities.Where(p => p.ParentPageCode == entity.PageCode).ToList();
            foreach (var item in list)
            {
                item.Children.AddRange(PageTemplateList(item, entities));
            }
            return list;
        }

    }
}
